import {
  cadAppLog,
  CMEVENTS,
  designTreeMenuManager,
  EventsRes,
  FeatureManager,
  pickedFaceData,
  pickedLineData,
  pickedModelData,
  pickedVertexData,
  preventKeys,
  STATE,
} from '@amcax/base';
import { Picker3D, PickerAssembly, PickerMgr } from '@amcax/renderer';
import { measureRenderManager } from '@app-base/manager/MeasureRenderManager';
import { refDocNodes } from '@app-base/pages/product-support/assembly-funcs';
import { DefaultContextMenu } from '@app-cad-env/nextcad/widgets/ContextMenu/DefaultContextMenu';
import { PartLeftPanelEvents } from '@app-cad-env/nextcad/widgets/LeftPanel/types';
import { ProductNodeMenu } from '@app-cad-env/product/widgets/LeftPanel/ContextMenu';
import { CIRCLE_BAR_EVENTS, KEYBOARD_KEY } from '@app-cad/common/Constants';
import { ContextMenuEvents } from '@app-cad/environments/nextcad/widgets/ContextMenu/DefaultContextMenu/events';
import { docMgr, userEvents } from '@app-cad/module';
import { allParts } from '@app-cad/pages/product-support/part-funcs';
import { AssemblySmartMover, invokeEditCommand } from '../utils';
import { EventCenter3D } from './EventCenter3D';

/* 事件模块 */
export class DefaultEventCenter extends EventCenter3D {
  id = 'default';
  timer = null;
  isLongPress = false;
  clickTimerCount = 0;
  clickTimer: NodeJS.Timeout;

  editTarget:
    | pickedVertexData
    | pickedLineData
    | pickedFaceData
    | pickedModelData;

  private readonly assemblySmartMover =
    this.picker instanceof PickerAssembly
      ? new AssemblySmartMover(this.picker)
      : null;

  private updateEditTarget() {
    // 点的拾取 通过hover拿到点的信息
    this.editTarget = [
      this.picker.getHoverOnVertex(),
      this.picker.getHoverOnLine(),
      this.picker.getHoverOnMesh(),
      this.picker.getHoverOnModel(),
    ].find((i) => i?.assisObj != null);
  }

  onCanvasPointerDown(ev: EventsRes<MouseEvent>): void {
    this.timer = setTimeout(() => {
      cadAppLog('set isLongPress true');
      this.isLongPress = true;
    }, 300);
    super.onCanvasPointerDown(ev);

    if (
      FeatureManager.isFeatureEnabled('assemble-smart-move') &&
      ev.button.onLeft &&
      this.assemblySmartMover
    ) {
      this.updateEditTarget();

      if (!this.editTarget?.assisObj) {
        return;
      }

      const { modelDxid, lineId, vertexId, meshId } = this.editTarget
        .assisObj as any;
      const key = modelDxid || lineId || vertexId || meshId;
      const smartMoveTarget = refDocNodes.get(key?.split(':')[0]);

      if (smartMoveTarget) {
        this.assemblySmartMover.prepareMove(smartMoveTarget, {
          x: ev.event.clientX,
          y: ev.event.clientY,
        });
      }
    }
  }

  onCanvasPointerMove(ev: EventsRes<MouseEvent>): EventsRes<MouseEvent> {
    if (ev.button.onLeft && this.assemblySmartMover) {
      this.assemblySmartMover.move({
        x: ev.event.clientX,
        y: ev.event.clientY,
      });
    }

    return super.onCanvasPointerMove(ev);
  }

  onCanvasPointerup(ev: EventsRes<PointerEvent>) {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }

    if (ev.button.onLeft && this.assemblySmartMover) {
      this.assemblySmartMover.finishMove();
    }

    const { button } = ev;

    super.onCanvasPointerup(ev);

    if (button.onLeft && this.picker instanceof Picker3D) {
      this.picker.clearSelectedModel();
      this.clickTimerCount = this.clickTimerCount + 1;

      if (this.clickTimerCount === 1) {
        this.updateEditTarget();
        this.clickTimer = setTimeout(() => {
          this.clickTimerCount = 0;
          this.editTarget = null;
        }, 300);
      } else {
        // 清除单击事件的定时器
        clearTimeout(this.clickTimer);
        this.clickTimerCount = 0;

        if (this.state === STATE.DEFAULT) {
          if (
            this.editTarget?.objInfo != null ||
            this.editTarget?.idInfo != null
          ) {
            const objInfo = docMgr.getDocumentObjectById(
              this.editTarget.idInfo.o,
            );
            invokeEditCommand(objInfo);

            userEvents.emit(CMEVENTS.HIGHLIGHT_OBJECTS, [objInfo.dxid]);

            return ev;
          }
        }
      }
    }

    // @ted 临时需求，右键canvas元素可打开菜单
    // 后续应当会正常走产品优化行为
    if (ev.button.onRight) {
      this.clickTimerCount = this.clickTimerCount + 1;

      if (this.clickTimerCount === 1) {
        this.clickTimer = setTimeout(() => {
          this.clickTimerCount = 0;
        }, 300);
      } else if (!this.editTarget) {
        // 清除单击事件的定时器
        clearTimeout(this.clickTimer);
        this.clickTimerCount = 0;

        if (this.state === STATE.DEFAULT) {
          userEvents.emit(CIRCLE_BAR_EVENTS.CIRCLE_BAR_SHOW, ev);
        }
      }

      if (measureRenderManager.hoveredObject != null) {
        const documentObject = docMgr.getDocumentObjectById(
          measureRenderManager.hoveredObject.measureResult.id,
        );
        setTimeout(
          () =>
            userEvents.emit(PartLeftPanelEvents.ScrollTo, documentObject.dxid),
          500,
        );

        setTimeout(() => {
          designTreeMenuManager.show(ev.event, DefaultContextMenu.id, {
            documentObject,
            selectedObjects: [documentObject],
          });
        });
        return ev;
      }
      cadAppLog('isLongPress', this.isLongPress);
      this.updateEditTarget();
      if (this.editTarget != null) {
        const objInfo = docMgr.getDocumentObjectById(this.editTarget.idInfo.o);
        if (objInfo != null && !this.isLongPress) {
          setTimeout(() => {
            if (this.editTarget) {
              userEvents.emit(
                PartLeftPanelEvents.ScrollTo,
                this.editTarget.idInfo.o,
              );
            }
          }, 500);

          setTimeout(() => {
            designTreeMenuManager.show(ev.event, DefaultContextMenu.id, {
              documentObject: objInfo,
              selectedObjects: [objInfo],
            });
          });
        } else if (this.picker instanceof PickerAssembly) {
          const node = allParts.get(this.editTarget.objInfo.dxid.split(':')[0]);
          if (node) {
            setTimeout(() =>
              designTreeMenuManager.show(ev.event, ProductNodeMenu.id, node),
            );
          }
        }
      }
      cadAppLog('set isLongPress false');
      this.isLongPress = false;
    }

    return ev;
  }

  /**
   *
   * 键盘事件
   */

  onKeyUp(ev: EventsRes<KeyboardEvent>) {
    const { event } = ev;
    if (preventKeys.indexOf(event.key) != -1) {
      event.preventDefault();
    }

    super.onKeyUp(ev);

    // 快捷复制
    if (
      (event.key === KEYBOARD_KEY.KEY_C ||
        event.key === KEYBOARD_KEY.KEY_UPPERCASE_C) &&
      event.ctrlKey === true &&
      (event.target as any)?.tagName !== 'INPUT'
    ) {
      userEvents.emit(ContextMenuEvents.Copy, event);
    }

    // 快捷粘贴
    if (
      (event.key === KEYBOARD_KEY.KEY_V ||
        event.key === KEYBOARD_KEY.KEY_UPPERCASE_V) &&
      event.ctrlKey === true &&
      (event.target as any)?.tagName !== 'INPUT'
    ) {
      userEvents.emit(ContextMenuEvents.Paste, event);
    }

    // 快捷删除
    if (
      event.key === KEYBOARD_KEY.DELETE &&
      (event.target as any)?.tagName !== 'INPUT'
    ) {
      userEvents.emit(ContextMenuEvents.Delete, event);
    }

    return ev;
  }
}

let eventCenter: DefaultEventCenter;

/**
 * Returns the singleton instance of DefaultEventCenter.
 * The `picker` parameter is only used for initialization, and won't affect the picker of the result in further calls.
 *
 * @param {Picker3D | PickerAssembly} [picker=PickerMgr.getPicker<Picker3D>('3d')] - The picker used for initialization.
 * @returns {DefaultEventCenter} The singleton instance of DefaultEventCenter.
 */
export const defaultEventCenter = (
  picker: Picker3D | PickerAssembly = PickerMgr.getPicker<Picker3D>('3d'),
): DefaultEventCenter => {
  if (eventCenter == null) {
    eventCenter = new DefaultEventCenter(picker);
  }

  return eventCenter;
};
